package xyz.archknight.app.loginput.dictionary.gen.ui

import com.formdev.flatlaf.FlatLaf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory
import xyz.archknight.app.loginput.dictionary.gen.bean.ActionProtocol
import xyz.archknight.app.loginput.dictionary.gen.bean.DatabaseProtocol
import xyz.archknight.app.loginput.dictionary.gen.bean.Packet
import xyz.archknight.app.loginput.dictionary.gen.bean.RecordItem
import xyz.archknight.app.loginput.dictionary.gen.dao.Cache
import xyz.archknight.app.loginput.dictionary.gen.dao.DBUtils
import xyz.archknight.app.loginput.dictionary.gen.dao.Word
import xyz.archknight.app.loginput.dictionary.gen.service.*
import java.awt.BorderLayout
import java.awt.Dimension
import java.io.*
import javax.swing.JFileChooser
import javax.swing.JFrame
import javax.swing.JOptionPane
import javax.swing.filechooser.FileNameExtensionFilter

/**
 * 词库辅助工具主页面
 *
 * @author midnite
 * create at 2020-06-14 10:54 下午
 */
class CoreFrame(title: String) : JFrame(title) {
    private val toolbar = MainToolBar()
    private val mainFunctionPane = MainPane()
    private val statusBar = StatusBar()

    init {
        EventBus.toolbar.subscribe(this::eventRouter)
        createUI()
    }

    companion object {
        private val log = LoggerFactory.getLogger(CoreFrame::class.java)
    }

    private fun createUI() {
        size = Dimension(500, 700)
        minimumSize = Dimension(500, 700)

        with(contentPane) {
            layout = BorderLayout(8, 8)
            add(toolbar, BorderLayout.NORTH)
            add(mainFunctionPane, BorderLayout.CENTER)
            add(statusBar, BorderLayout.SOUTH)
        }

        defaultCloseOperation = EXIT_ON_CLOSE
        setLocationRelativeTo(null)

        FlatLaf.updateUI()
    }

    private fun eventRouter(signal: Packet<ActionProtocol, Int>) {
        when (signal.action) {
            ActionProtocol.ResetDatabase -> resetDatabase()
            ActionProtocol.LoadDatabase -> loadDatabase()
            ActionProtocol.SaveDatabase -> saveDatabase()
            ActionProtocol.OpenImport -> openImportDialog()
            ActionProtocol.OpenExport -> openExportDialog()
            ActionProtocol.MixCacheInDatabase -> transferCache()
        }
    }

    private fun openImportDialog() {
        val fileChooser = JFileChooser()
        fileChooser.fileFilter = FileNameExtensionFilter("落格输入法词库文件", "txt")
        val returnVal = fileChooser.showOpenDialog(this)
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            val dialog = ImportDialog(this)
            dialog.import(fileChooser.selectedFile.path)
            dialog.isVisible = true
        }
    }

    private fun openExportDialog() {
        val fileChooser = JFileChooser()
        fileChooser.fileFilter = FileNameExtensionFilter("落格输入法词库文件", "txt")
        val returnVal = fileChooser.showSaveDialog(this)
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            val dialog = ExportDialog(this)
            dialog.export(fileChooser.selectedFile.path)
            dialog.isVisible = true
        }
    }

    private fun resetDatabase() = GlobalScope.launch(Dispatchers.IO) {
        transaction {
            DBUtils.resetTables()
        }
        EventBus.dbChange(DatabaseProtocol.RefreshBoth)
    }

    private fun saveDatabase() {
        val fileChooser = JFileChooser()
        fileChooser.fileFilter = FileNameExtensionFilter("词库工具数据文件", "akdb")
        val returnVal = fileChooser.showSaveDialog(this)
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            GlobalScope.launch(Dispatchers.IO) {
                try {
                    saveDatabaseToFile(fileChooser.selectedFile.path)
                } catch (e: IOException) {
                    launch(Dispatchers.Swing) {
                        log.error(e.message)
                        e.printStackTrace()
                        JOptionPane.showMessageDialog(
                            this@CoreFrame,
                            "数据库保存到磁盘失败，请重试。",
                            "保存失败",
                            JOptionPane.ERROR_MESSAGE
                        )
                    }
                }
            }
        }
    }

    private fun loadDatabase() {
        val fileChooser = JFileChooser()
        fileChooser.fileFilter = FileNameExtensionFilter("词库工具数据文件", "akdb")
        val returnVal = fileChooser.showOpenDialog(this)
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            GlobalScope.launch(Dispatchers.IO) {
                try {
                    loadDatabaseFromFile(fileChooser.selectedFile)
                } catch (e: Exception) {
                    val message = when(e) {
                        is IOException -> "文件读写错误。"
                        is IllegalArgumentException -> "不正确的文件格式。"
                        else -> "未知错误。"
                    }
                    launch(Dispatchers.Swing) {
                        log.error(e.message)
                        e.printStackTrace()
                        JOptionPane.showMessageDialog(
                            this@CoreFrame,
                            "数据文件读取失败，请重试。$message",
                            "读取失败",
                            JOptionPane.ERROR_MESSAGE
                        )
                    }
                }
            }
        }
    }
}